//-------------------------------------------------------------------
//	Copyright (c) 2010-2012 Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#ifndef _UX_CONFIGURATION_FILE_PARSER_H
#define _UX_CONFIGURATION_FILE_PARSER_H

#include "../Core/CCore.h"
#include "ConfigTypes.h"
#include "IParser.h"

namespace Engine
{
namespace CoreSystems
{

	struct TConfigObjInfo
	{
		CMetaSetIterator  *	pIter;
		const string		sName;
		bool				bUsed;
		///
		TConfigObjInfo(): pIter(nullptr), bUsed(true) {}
		TConfigObjInfo(CMetaSetIterator *iter, const char *name): pIter(iter), sName(name), bUsed(false) {}
	};
	

	struct TConfigObjInfoConstructor
	{
		static void CreateDefault(TConfigObjInfo &e)				{}
		static void Create(TConfigObjInfo &e)						{}
		static void Destroy(TConfigObjInfo &e)						{ if ( e.pIter != nullptr ) e.pIter->Free(); }
		static void Copy(TConfigObjInfo &from, TConfigObjInfo &to)	{}
	};


	typedef tree< TConfigObjInfo, TConfigObjInfoConstructor >		static_obj_tree_t;
	typedef static_obj_tree_t::iterator								static_obj_node_t;
	typedef static_obj_tree_t::const_iterator						save_obj_node_t;


	class _EXPORT_ IConfigProcessStrategy
	{
	protected:
		static bool _s_CompareObjects(const TConfigObjInfo &sObj, const CConfigBaseType *pCfgObj);

	public:
		virtual bool CreateDynamic(const string &sTypeName, const char *pParams, CMetaSetIterator *&pIter) = 0;
		virtual void OnEndParseDynamic(CMetaSetIterator *pIter) = 0;
		virtual bool CreateStatic(static_obj_node_t &pObjects, const CConfigBaseType *pCfgObj, CMetaSetIterator *&pIter, bool &bNeedDelete) = 0;
	};



	//
	// Config Container
	//

	struct _EXPORT_ TConfigContainer : public CEngBaseObject
	{
		friend class Engine::CoreSystems::CConfig;
		friend struct TConfigObjTreeUpdater;

	private:
		string			_sFileName;
		config_tree_t	_sObjectsTree;
			
	private:
		TConfigContainer(const string &sFileName);
		~TConfigContainer();

		bool _DeleteTempObj() const;
		void _CheckObj(TConfigObjInfo &sInfo) const;
		static void _s_CheckObject(TConfigObjInfo &sInfo, void *pParametr);
		static void _s_RecursiveDeleteTempObj(config_node_t pNode);
		bool _RecursiveCreate(config_const_node_t pNode, CMetaSetIterator *pIter, IConfigProcessStrategy *pStrategy);
		bool _RecursiveProcessArray(config_const_node_t pNode, CMetaArrayIterator *pIter);
		bool _ProcessArrayElem(config_const_node_t pNode, CMetaArrayIterator *pIter);
		bool _ProcessStructElem(config_const_node_t pNode, CMetaStructIterator *pIter);
		bool _ProcessInitList(config_const_node_t pNode, CMetaSetIterator *pIter);
		bool _RecursiveSet(config_const_node_t pNode, static_obj_node_t pObjects, CMetaSetIterator *pIter, IConfigProcessStrategy *pStrategy);

	public:
		bool ClearTree();

		bool Process(IConfigProcessStrategy *pStrategy = nullptr);
		bool Process(static_obj_node_t pObjects, IConfigProcessStrategy *pStrategy = nullptr);

		config_const_node_t	GetObjTree()	const	{ return _sObjectsTree.GetFirst(); }
		const string	&	GetFileName()	const	{ return _sFileName; }

		// CEngBaseObject //
		virtual void  Release();
	};



	//
	// Config System
	//

	class _EXPORT_ CConfig : public CEngBaseObject
	{
		friend class Engine::CoreSystems::CCore;

	private:
		array< TConfigContainer *>	_aContainers;
		array< IParser *>			_aParsers;
		string_array_t				_aDefDirectories;
		IParser					*	_pOCFParser;
		string						_sParsedFilesDir;
		bool						_bSaveParsed;

	protected:
		CConfig();
		~CConfig();

		bool  Init();
		void  _Clear();

		// CEngBaseObject //
		virtual void Release();

	public:
		bool Parse(IParser *pParser, IFilePtr pFile, TConfigContainer *&pObj, uint uFileSize = 0, const array<string> *pDirectory = nullptr);
		bool Parse(IFilePtr pFile, TConfigContainer *&pObj, uint uFileSize = 0, const array<string> *pDirectory = nullptr);
		bool Parse(const char *pFileName, TConfigContainer *&pObj, const array<string> *pDirectory = nullptr);

		bool Save(IFilePtr pFile, save_obj_node_t pObjects);
		bool Save(const char *pFileName, save_obj_node_t pObjects);

		bool AddDirectory(const string &sDirectory);
		bool RemoveDirectory(const string &sDirectory);
		void ClearDerectories();

		bool GetParser(const char *pFileExt, IParser *&pParser);
		bool RegisterParser(IParser *pParser, bool bHighPriority = false);
		bool UnregisterParser(IParser *pParser);

		bool RemoveContainer(TConfigContainer *pCC);

		// debug
		void SaveParsedFiles(bool bSave);
		bool SetParsedFilesDirectory(const char *pDir);
	};

//-------------------------------------------------------------------

}	// CoreSystems
}	// Engine

#endif	// _UX_CONFIGURATION_FILE_PARSER_H